package br.com.rookgraph.gui;

import java.awt.EventQueue;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.swing.AbstractListModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;

import br.com.rookgraph.run.ArenaAlgoritmos;
import br.com.rookgraph.utils.EnumGeracaoArvore;
import br.com.rookgraph.utils.ExecuteHeuristicas;

import java.awt.Color;

import javax.swing.JSeparator;
import javax.swing.JTextArea;

public class JanelaArvores {

	private JFrame frmArena;
	private JTextField txtSelecionarArquivo;
	private JLabel nomeArquivoGrafo;
	private JList<?> listaArvores;
	private JList<?> listaConfiguracoes;
	private JButton buttonAdicionarConfig;
	private static JTextArea console;
	private DefaultListModel<EnumGeracaoArvore> dataModel = new DefaultListModel<EnumGeracaoArvore>();

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					JanelaArvores window = new JanelaArvores();
					window.frmArena.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 * @throws UnsupportedLookAndFeelException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws ClassNotFoundException 
	 */
	public JanelaArvores() throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {
//		UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmArena = new JFrame();
		frmArena.setResizable(false);
		frmArena.setTitle("Arena");
		frmArena.setBounds(100, 100, 437, 556);
		frmArena.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frmArena.getContentPane().setLayout(null);
		
		criarListas();
		
		criarLabels();

		criarAcessorios();
		
		criarBotoes(frmArena);
		
		criarBotaoAdicionar();

		criarBotaoRemover();
		
		criarBotaoFechar();

		criarBotaoExecutar();
		
		configurarPainel();
	}

	private void configurarPainel() {
		dataModel.addElement(EnumGeracaoArvore.LARGURA);
		dataModel.addElement(EnumGeracaoArvore.PRODUNDIDADE);
		dataModel.addElement(EnumGeracaoArvore.KRUSKAL);
	}

	private void criarAcessorios() {
		txtSelecionarArquivo = new JTextField();
		txtSelecionarArquivo.setForeground(Color.GRAY);
		txtSelecionarArquivo.setText("selecionar arquivo");
		txtSelecionarArquivo.setToolTipText("");
		txtSelecionarArquivo.setBackground(UIManager.getColor("TextPane.disabledBackground"));
		txtSelecionarArquivo.setEditable(false);
		txtSelecionarArquivo.setBounds(10, 11, 294, 20);
		frmArena.getContentPane().add(txtSelecionarArquivo);
		txtSelecionarArquivo.setColumns(10);
	}

	private void criarBotaoRemover() {
		JButton btnRemover = new JButton("-");
		btnRemover.setToolTipText("Remover configuração");
		btnRemover.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				int index = listaConfiguracoes.getSelectedIndex();
				dataModel.removeElement(listaConfiguracoes.getSelectedValue());
				listaConfiguracoes.setSelectedIndex(index);
			}
		});
		btnRemover.setBounds(191, 119, 52, 23);
		frmArena.getContentPane().add(btnRemover);
	}

	private void criarLabels() {
		JLabel lblConfiguracoes = new JLabel("Configurações");
		lblConfiguracoes.setHorizontalAlignment(SwingConstants.CENTER);
		lblConfiguracoes.setFont(new Font("Tahoma", Font.BOLD, 11));
		lblConfiguracoes.setBounds(253, 61, 172, 14);
		frmArena.getContentPane().add(lblConfiguracoes);
		
		JLabel lblGeraoDarvore = new JLabel("Árvores");
		lblGeraoDarvore.setFont(new Font("Tahoma", Font.BOLD, 11));
		lblGeraoDarvore.setHorizontalAlignment(SwingConstants.CENTER);
		lblGeraoDarvore.setBounds(9, 61, 205, 14);
		frmArena.getContentPane().add(lblGeraoDarvore);
		
		nomeArquivoGrafo = new JLabel("");
		nomeArquivoGrafo.setFont(new Font("Tahoma", Font.BOLD, 11));
		nomeArquivoGrafo.setBounds(10, 36, 404, 14);
		frmArena.getContentPane().add(nomeArquivoGrafo);
	}

	private void criarBotaoFechar() {
		JButton btnFechar = new JButton("X");
		btnFechar.setToolTipText("Fechar janela");
		btnFechar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
		btnFechar.setBounds(191, 187, 52, 23);
		frmArena.getContentPane().add(btnFechar);
	}

	private void criarBotaoExecutar() {
		JButton btnExecutar = new JButton(">");
		btnExecutar.setToolTipText("Executar configurações");
		btnExecutar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				new Worker().execute();
			}
		});
		
		btnExecutar.setBounds(191, 153, 52, 23);
		frmArena.getContentPane().add(btnExecutar);
		
		JSeparator separator = new JSeparator();
		separator.setBounds(9, 222, 412, 2);
		frmArena.getContentPane().add(separator);
		
		console = new JTextArea();
		console.setBounds(10, 234, 415, 283);
		frmArena.getContentPane().add(console);
		
		JScrollPane scrollPane = new JScrollPane(console, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollPane.setBounds(10, 234, 415, 283);
		
		frmArena.getContentPane().add(scrollPane);
	}

	private void criarBotaoAdicionar() {
		// Botão para adicionar configuração escolhida à lista de configurações
		buttonAdicionarConfig = new JButton("+");
		buttonAdicionarConfig.setToolTipText("Adicionar configuração");
		buttonAdicionarConfig.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Object arvoreSelecionada = listaArvores.getSelectedValue();
				
				adicionarConfig(arvoreSelecionada);
			}

			private void adicionarConfig(Object arvoreSelecionada) {
				Integer posicao = 0;
				
				if (arvoreSelecionada != null) {
					Enumeration<EnumGeracaoArvore> configuracoes = dataModel.elements();
					
					// Percorre a lista de configurações já definida
					while (configuracoes.hasMoreElements()) {
						EnumGeracaoArvore elemento = configuracoes.nextElement();
						
						// Se já tiver uma configuração com a heurística escolhida para entrar agora, deve ser feita uma substituição
						if (elemento.toString().equals((String) arvoreSelecionada)) {
							posicao = dataModel.indexOf(elemento);
							dataModel.removeElement(elemento);
							break;
						}
					}
					
					EnumGeracaoArvore arvore = EnumGeracaoArvore.buscarValorPorNome((String) arvoreSelecionada);
					dataModel.add(posicao, arvore);
				} else {
					System.out.println("Selecione uma heurística e um método para a geração da árvore.");
				}
			}
		});
		buttonAdicionarConfig.setBounds(191, 85, 52, 23);
		frmArena.getContentPane().add(buttonAdicionarConfig);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void criarListas() {
		// Lista de árvores
		listaArvores = new JList();
		listaArvores.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		listaArvores.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		listaArvores.setModel(new AbstractListModel() {
			private static final long serialVersionUID = 3133581432879199714L;
			
			String[] values = getNomeArvores();
			public int getSize() {
				return values.length;
			}
			
			public Object getElementAt(int index) {
				return values[index];
			}
		});
		listaArvores.setBounds(9, 86, 172, 124);
		frmArena.getContentPane().add(listaArvores);
		
		// Lista de configurações
		listaConfiguracoes = new JList<EnumGeracaoArvore>(dataModel);
		listaConfiguracoes.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		listaConfiguracoes.setBounds(253, 86, 172, 124);
		frmArena.getContentPane().add(listaConfiguracoes);
	}

	private void criarBotoes(Frame mainFrame) {
		final FileDialog fileDialog = new FileDialog(mainFrame,"Selecionar arquivo");
		
		// Botão para selecionar o arquivo de entrada com os grafos
		JButton btnSelecionarGrafo = new JButton("Selecionar Grafo");
		btnSelecionarGrafo.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fileDialog.setVisible(true);
				if (fileDialog.getDirectory() != null) {
					txtSelecionarArquivo.setText(fileDialog.getDirectory() + fileDialog.getFile());
					nomeArquivoGrafo.setText(fileDialog.getFile());
				}
			}
		});
		btnSelecionarGrafo.setBounds(314, 10, 111, 23);
		frmArena.getContentPane().add(btnSelecionarGrafo);
	}

	public String[] getNomeHeuristicas() {
		ArrayList<String> nomes = new ArrayList<String>();
		for (ExecuteHeuristicas h : ExecuteHeuristicas.values()) {
			nomes.add(h.toString());
		}
		
		return nomes.toArray(new String[nomes.size()]);
	}
	
	public String[] getNomeArvores() {
		ArrayList<String> nomes = new ArrayList<String>();
		for (EnumGeracaoArvore h : EnumGeracaoArvore.values()) {
			nomes.add(h.toString());
		}
		
		return nomes.toArray(new String[nomes.size()]);
	}

	public static void logar(String texto) {
		console.append(texto + "\n");
		console.setCaretPosition(console.getText().length());
	}

	public static void logarMesmaLinha(String texto) {
		console.append(texto);
		console.setCaretPosition(console.getText().length());
	}

	public class Worker extends SwingWorker<String, String> {
	    @Override
	    protected String doInBackground() throws Exception {
			try {
				if (nomeArquivoGrafo.getText().isEmpty()) {
					logar("Selecione um arquivo de entrada.");
				} else {
					String fileName =  nomeArquivoGrafo.getText();
					ArenaAlgoritmos.executarMultArvores(txtSelecionarArquivo.getText(), fileName, dataModel.elements());
				}
			} catch (IOException | CloneNotSupportedException e) {
				e.printStackTrace();
			}
			
	        return null;
	    }
	}
}
